﻿using SiMay.Sockets.Tcp;
using SiMay.Sockets.Tcp.Client;
using SiMay.Sockets.Tcp.Session;
using SiMay.Sockets.Tcp.TcpConfiguration;
using SyncFileCommon.Class;
using SyncFileCommon.Model;
using System.Collections.Concurrent;
using System.Net;

namespace SyncFileCommon.BLL
{

    public delegate void ClientEventHandler(TcpSocketCompletionNotify e, TcpSocketSaeaSession session);

    public class ClientBLL
    {

        /// <summary>
        /// 触发消息事件
        /// </summary>
        public Action<string, string> MessageEvent;

        /// <summary>
        /// 设置下载文件保存路径事件
        /// </summary>
        public Func<string, long, string> FileDownloadBeginEvent;


        /// <summary>
        /// 连接到服务器的Session
        /// </summary>
        public TcpSocketSaeaSession Session { get; set; } = null;

        /// <summary>
        /// 客户端触发的事件
        /// </summary>
        public event ClientEventHandler ClientEvent;

        /// <summary>
        /// TCPClientSocket服务
        /// </summary>
        public TcpSocketSaeaClientAgent TcpClient = null;

        /// <summary>
        /// 当前执行的同步文件计划
        /// </summary>
        public SyncPlanModel SyncPlan = null;

        /// <summary>
        /// 保存删除文件的文件夹路径
        /// </summary>
        public string DeleteFileDir = string.Empty;

        /// <summary>
        /// 当前下载的子文件夹信息路径
        /// </summary>
        public DownLoadDirState DownLoadDir = new DownLoadDirState();

        /// <summary>
        /// 当前下载的文件路径
        /// </summary>
        public string DownLoadFileName = string.Empty;

        public Action UserLogin;

        /// <summary>
        /// 待获取信息的文件夹信息列表
        /// </summary>
        public Queue<string> DownLoadDirList = new Queue<string>();

        /// <summary>
        /// 待下载的文件路径列表
        /// </summary>
        public ConcurrentDictionary<string, string> DownLoadFileList = new ConcurrentDictionary<string, string>();




        /// <summary>
        /// 客户端连接服务器
        /// </summary>
        /// <param name="ip">服务器IP</param>
        /// <param name="port">端口</param>
        public bool ClientConnect(string ip, int port)
        {
            //对服务器发起连接
            TcpSocketSaeaClientConfiguration clientConfig = new TcpSocketSaeaClientConfiguration();
            clientConfig.CompressTransferFromPacket = false;

            TcpClient = TcpSocketsFactory.CreateClientAgent(TcpSocketSaeaSessionType.Packet, clientConfig, Client_CompletetionNotify);

            return TcpClient.ConnectToServer(new IPEndPoint(IPAddress.Parse(ip), port));

        }

        /// <summary>
        /// 文件下载前设置文件保存路径
        /// </summary>
        /// <param name="serverFilePath">服务器上文件路径</param>
        /// <param name="fileSize">文件大小(字节数)</param>
        /// <returns></returns>
        private string FileDownloadBegin(string serverFilePath, long fileSize)
        {
            if (DownLoadFileList.ContainsKey(serverFilePath))
            {
                return DownLoadFileList[serverFilePath];
            }
            return FileDownloadBeginEvent?.Invoke(serverFilePath, fileSize);
        }

        /// <summary>
        /// 客户端触发事件
        /// </summary>
        /// <param name="e"></param>
        /// <param name="session"></param>
        private void Client_CompletetionNotify(TcpSocketCompletionNotify e, TcpSocketSaeaSession session)
        {
            if (e == TcpSocketCompletionNotify.OnConnected)
            {
                Session = session;
            }

            switch (e)
            {
                case TcpSocketCompletionNotify.OnConnected:
                    //session初始化完成连接的事件
                    //调用session.SendAsync();对session发送消息
                    //调用session.Close(true)断开session连接，并通知断开事件
                    //可在session.AppTokens中绑定应用对象，以便在其他异步事件中调用
                    this.UserLogin?.Invoke();
                    this.ClientEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnSend:
                    //session发送数据通知事件
                    //session.SendTransferredBytes == 以发送数据长度
                    this.ClientEvent?.Invoke(e, session);
                    break;
                case TcpSocketCompletionNotify.OnDataReceiveing:
                    //session数据接收通知事件
                    //session.ReceiveBytesTransferred == 本次接收数据长度 
                    this.ClientEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnDataReceived:
                    //Packet模式session自动处理分包的完成事件

                    if (SyncPlan != null)
                    {


                        byte[] pack = session.CompletedBuffer;//完整数据包
                        var _rd = SessionHelper.RecieverData(session, pack, FileDownloadBegin);
                        if (new SessionHelper.DataPackType[] { SessionHelper.DataPackType.DataOnePack, SessionHelper.DataPackType.DataMultiplePack, SessionHelper.DataPackType.FileDataPack }.Contains(_rd.PackType))
                        {
                            if (_rd.DataAllLength == _rd.RedeiverLength)
                            {
                                if (_rd.PackType == SessionHelper.DataPackType.FileDataPack)
                                {
                                    string _cs;
                                    DownLoadFileList.Remove(DownLoadFileName, out _cs);
                                    DownLoadFileName = "";
                                    DownLoadFile();
                                    DownLoadDirInfo();
#if DEBUG
                                    LogHelper.WriteLogToFile("ClientLog", DateTime.Now.ToString("HH:mm:ss.fff") + " " + "下载文件完成:" + System.Text.Encoding.UTF8.GetString(_rd.Data));
#endif
                                    MessageEvent?.Invoke("下载文件完成", "文件路径:" + System.Text.Encoding.UTF8.GetString(_rd.Data));
                                }
                                else
                                {
                                    switch (MessageHelper.GetMessageHead<MessageHead>(_rd.Data))
                                    {
                                        case MessageHead.JsonString:
                                            {
                                                string _s = MessageHelper.GetMessageStringData(_rd.Data);
                                                JsonHelper _json = new JsonHelper(_s);
                                                string _messageType = _json.GetVar("MessageType");
                                                switch (_messageType)
                                                {
                                                    case "LoginOK":
                                                        {
                                                            if (session.AppTokens == null)
                                                            {
                                                                session.AppTokens = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
                                                            }
                                                            session.AppTokens.AddOrUpdate("LoginState", "OK", (key, oldValue) => { return "OK"; });
                                                            MessageEvent?.Invoke("登录", "登录成功");
                                                            if (SyncPlan != null)
                                                            {
                                                                //开始同步文件
                                                                //获取目录下所有文件夹


                                                                DownLoadDir.DownLoadSubDirInfoOK = true;
                                                                DownLoadDir.DownLoadFileInfoOK = true;
                                                                DownLoadDirList.Enqueue(SyncPlan.DirPath);
                                                                DownLoadDirInfo();
                                                            }


                                                            break;
                                                        }
                                                    case "LoginFail":
                                                        {
                                                            MessageEvent?.Invoke("登录", "用户名或密码错误");

                                                            break;
                                                        }
                                                    case "SubDirectoryInfo":
                                                        {
                                                            //返回了子文件夹信息
                                                            string _data = _json.GetVar("Data");
                                                            string _serverDirPath = _json.GetVar("DirPath");
                                                            List<string> _dirPathList = JsonHelper.GetObjectFromJsonStr<List<string>>(_data);
                                                            MessageEvent?.Invoke("获取子文件夹信息", "获取成功:" + _serverDirPath);

                                                            if (DownLoadDir.DirPath == _serverDirPath)
                                                            {
                                                                DownLoadDir.DownLoadSubDirInfoOK = true;
                                                            }

                                                            List<string> _clientDirList = FileHelper.GetDirectorySubDirectory(SyncPlan.SaveDirPath + _serverDirPath.Replace(SyncPlan.DirPath, ""));
                                                            foreach (string _clientDir in _clientDirList)
                                                            {
                                                                if (_dirPathList.Contains(SyncPlan.DirPath + _clientDir.Replace(SyncPlan.SaveDirPath, "")))
                                                                {
                                                                    //移除已经存在的文件夹信息
                                                                    _dirPathList.Remove(SyncPlan.DirPath + _clientDir.Replace(SyncPlan.SaveDirPath, ""));

                                                                    DownLoadDirList.Enqueue(SyncPlan.DirPath + _clientDir.Replace(SyncPlan.SaveDirPath, ""));
                                                                }
                                                                else
                                                                {
                                                                    //将服务器上不存在的文件夹移动到删除备份文件夹
                                                                    try
                                                                    {
                                                                        Directory.Move(_clientDir, DeleteFileDir + @"\" + DateTime.Now.ToString("yyyyMMddHHmmss") + @"\" + SyncPlan.DirPath.Replace(@"\", "-") + _clientDir.Replace(SyncPlan.SaveDirPath, ""));
                                                                    }
                                                                    catch
                                                                    {
                                                                        FileHelper.CopyDirectory(_clientDir, DeleteFileDir + @"\" + DateTime.Now.ToString("yyyyMMddHHmmss") + @"\" + SyncPlan.DirPath.Replace(@"\", "-") + _clientDir.Replace(SyncPlan.SaveDirPath, ""));
                                                                        Directory.Delete(_clientDir);
                                                                    }



                                                                }
                                                            }


                                                            foreach (string _dirPath in _dirPathList)
                                                            {
                                                                //转换服务器文件夹路径为客户端路径
                                                                string _clientDirPath = SyncPlan.SaveDirPath + _dirPath.Replace(SyncPlan.DirPath, "");


                                                                if (!Directory.Exists(_clientDirPath))
                                                                {
                                                                    Directory.CreateDirectory(_clientDirPath);
                                                                }

                                                                DownLoadDirList.Enqueue(_dirPath);



                                                            }
                                                            DownLoadDirInfo();
                                                            break;
                                                        }
                                                    case "DirFileInfo":
                                                        {
                                                            //返回了文件信息
                                                            string _data = _json.GetVar("Data");
                                                            string _serverDirPath = _json.GetVar("DirPath");
                                                            List<FileData> _fileDataList = JsonHelper.GetObjectFromJsonStr<List<FileData>>(_data);

                                                            MessageEvent?.Invoke("获取文件信息", "获取成功:" + _serverDirPath);

                                                            if (DownLoadDir.DirPath == _serverDirPath)
                                                            {
                                                                DownLoadDir.DownLoadFileInfoOK = true;
                                                            }

                                                            List<FileData> _clientFileDataList = FileHelper.GetDirectoryFile(SyncPlan.SaveDirPath + _serverDirPath.Replace(SyncPlan.DirPath, ""));
                                                            foreach (FileData _clientFileData in _clientFileDataList)
                                                            {
                                                                FileData _serverFileData = _fileDataList.Find(it => it.FileName.Contains(SyncPlan.DirPath + _clientFileData.FileName.Replace(SyncPlan.SaveDirPath, "")));
                                                                if (_serverFileData != null)
                                                                {
                                                                    //如果文件已存在，判断文件是否已经改改变，如果没有改变删除记录，否则删除本地文件
                                                                    if (_serverFileData.FileSize == _clientFileData.FileSize && _serverFileData.LastUpdateTime == _clientFileData.LastUpdateTime)
                                                                    {
                                                                        _fileDataList.Remove(_serverFileData);
                                                                    }
                                                                }
                                                                else
                                                                {
                                                                    //将服务器上没有的文件备份到备份文件夹
                                                                    try
                                                                    {
                                                                        string _fileDir = FileHelper.GetFileDirectoryName(DeleteFileDir + @"\" + DateTime.Now.ToString("yyyyMMddHHmmss") + @"\" + SyncPlan.DirPath.Replace(@"\", "_") + _clientFileData.FileName.Replace(SyncPlan.SaveDirPath, ""));
                                                                        if (!Directory.Exists(_fileDir))
                                                                        {
                                                                            Directory.CreateDirectory(_fileDir);
                                                                        }
                                                                        File.Move(_clientFileData.FileName, DeleteFileDir + @"\" + DateTime.Now.ToString("yyyyMMddHHmmss") + @"\" + SyncPlan.DirPath.Replace(@"\", "_") + _clientFileData.FileName.Replace(SyncPlan.SaveDirPath, ""));
                                                                    }
                                                                    catch
                                                                    {

                                                                    }


                                                                }



                                                            }


                                                            foreach (FileData _fileData in _fileDataList)
                                                            {
                                                                //转换文件路径
                                                                string _clientDirPath = SyncPlan.SaveDirPath + _fileData.FileName.Replace(SyncPlan.DirPath, "");
                                                                //插入下载缓存列表
#if DEBUG
                                                                LogHelper.WriteLogToFile("ClientLog", DateTime.Now.ToString("HH:mm:ss.fff") + " " + "添加文件到下载列表:" + _fileData.FileName);
#endif
                                                                DownLoadFileList.TryAdd(_fileData.FileName, _clientDirPath);
                                                                DownLoadFile();

                                                            }

                                                            DownLoadDirInfo();
                                                            break;
                                                        }
                                                }


                                                break;
                                            }

                                    }
                                }
                            }
                            else
                            {
                                //MessageEvent?.Invoke("接收消息中", "接收消息中:[" + _rd.RedeiverLength.ToString() + "/" + _rd.DataAllLength.ToString() + "]");
                            }
                        }

                    }
                    this.ClientEvent?.Invoke(e, session);

                    break;
                case TcpSocketCompletionNotify.OnClosed:
                    //session断开通知事件
                    this.ClientEvent?.Invoke(e, session);
                    break;
            }

        }

        /// <summary>
        /// 下载子文件夹信息
        /// </summary>
        public void DownLoadDirInfo()
        {
            if (string.IsNullOrWhiteSpace(DownLoadFileName) && DownLoadDirList.Count > 0 && DownLoadFileList.Count == 0)
            {
                if (DownLoadDir.DownLoadSubDirInfoOK && DownLoadDir.DownLoadFileInfoOK)
                {
                    DownLoadDir.DirPath = DownLoadDirList.Dequeue();
                    DownLoadDir.DownLoadSubDirInfoOK = false;
                    DownLoadDir.DownLoadFileInfoOK = false;
                    JsonHelper _clientJson = new JsonHelper();
                    _clientJson.AddVar("MessageType", "GetDirSubDirectory");
                    _clientJson.AddVar("DirPath", DownLoadDir.DirPath);
                    SessionHelper.SendData(Session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, _clientJson.JsonStr));


                    _clientJson = new JsonHelper();
                    _clientJson.AddVar("MessageType", "GetDirFileInfo");
                    _clientJson.AddVar("DirPath", DownLoadDir.DirPath);
                    SessionHelper.SendData(Session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, _clientJson.JsonStr));
                }

            }
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        public void DownLoadFile()
        {
            if (string.IsNullOrWhiteSpace(DownLoadFileName) && DownLoadFileList.Count > 0)
            {
                DownLoadFileName = DownLoadFileList.Keys.ToList()[0];
                JsonHelper _clientJson = new JsonHelper();
                _clientJson.AddVar("MessageType", "DownFile");
                _clientJson.AddVar("FilePath", DownLoadFileName);
                SessionHelper.SendData(Session, MessageHelper.CopyMessageHeadTo(MessageHead.JsonString, _clientJson.JsonStr));
            }
        }

        /// <summary>
        /// 客户端断开连接
        /// </summary>
        public void ClientDisConnect()
        {
            if (TcpClient != null)
            {
                //断开所有连接，并通知断开事件
                TcpClient.DisconnectAll(true);
            }

        }



    }

    /// <summary>
    /// 下载文件夹信息状态
    /// </summary>
    public class DownLoadDirState
    {
        /// <summary>
        /// 文件夹路径
        /// </summary>
        public string DirPath { get; set; } = string.Empty;

        /// <summary>
        /// 是否下载子文件夹信息成功
        /// </summary>
        public bool DownLoadSubDirInfoOK { get; set; } = false;

        /// <summary>
        /// 是否下载文件夹下文件信息成功
        /// </summary>
        public bool DownLoadFileInfoOK { get; set; } = false;
    }
}
